﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace SharepointLogReader
{
    class LogReader
    {
        #region Funcs
        private Action<string> _AddSearchResult;
        private Action<string> _AddLog;
        private Func<bool> _IsStopWork;
        #endregion

        #region MainFunctions
        public void Search(string dir, string searchText, Action<string> addSearchResult = null, Action<string> addLog = null, Func<bool> isStopWork = null)
        {
            SetFuncs(addSearchResult, addLog, isStopWork);

            AddLog("Start read");

            Search(dir, searchText);

            AddLog("End read");
        }
        #endregion

        #region AddFunctions
        private void Search(string dir, string searchText)
        {
            List<FileInfo> logFiles = GetLogsFiles(dir);
            SearchInFiles(searchText, logFiles);
        }
        private void SearchInFiles(string searchText, List<FileInfo> logFiles)
        {
            string searchResult = String.Empty;
            foreach (FileInfo file in logFiles)
            {
                AddLog(string.Format("Read log file '{0}'", file.FullName));
                searchResult = SearchInFile(file.FullName, searchText);

                if (!string.IsNullOrEmpty(searchResult))
                {
                    AddSearchResult(searchResult);
                }

                if (IsStopWork())
                {
                    break;
                }
            }
        }
        private List<FileInfo> GetLogsFiles(string dir)
        {
            string[] allFiles = Directory.GetFiles(dir);
            
            List<string> logFiles = new List<string>();
            foreach (string file in allFiles)
            {
                if (file.EndsWith(Consts.LOG_FILE_EXTENTIONS))
                {
                    logFiles.Add(file);
                }
            }

            List<FileInfo> logFilesInfo = new List<FileInfo>();
            foreach (string file in logFiles)
            {
                logFilesInfo.Add(new FileInfo(file));
            }

            logFilesInfo = logFilesInfo.OrderByDescending(x => x.CreationTime).Take(Settings.Current.MaxLogFiles).ToList();

            return logFilesInfo;
        }
        private string SearchInFile(string file, string searchText)
        {
            string[] logLines = GetLogLines(file, searchText);
            string searchResult = SearchInLines(logLines, searchText);
            return searchResult;
        }
        private string[] GetLogLines(string file, string searchText)
        {
            try
            {
                FileStream fs = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
                using (StreamReader sr = new StreamReader(fs))
                {
                    string fileData = sr.ReadToEnd();
                    {
                        string[] fileLines = fileData.Split('\n');
                        return fileLines;
                    }
                }
            }
            catch { }
            return new string[0];
        }
        private string SearchInLines(string[] lines, string searchText)
        {
            string[] searchResultMass = lines.Where(x => IsLineHaveSearchText(x, searchText)).Take(Settings.Current.MaxSearchLines).Select(x => GetLineSearchResult(x, searchText)).ToArray();
            string searchResult = string.Join(String.Empty, searchResultMass);
            return searchResult;
        }
        private bool IsLineHaveSearchText(string line, string searchText)
        {
            bool isLineHaveSearchText = line.Contains(searchText);
            return isLineHaveSearchText;
        }
        private string GetLineSearchResult(string line, string searchText)
        {
            const int startSearchTextTabNum = 7;
            const char tab = '\t';
            string[] logMass = line.Split(tab);

            if (logMass.Length > startSearchTextTabNum)
            {
                string lineSearchText = logMass[startSearchTextTabNum];
                if (lineSearchText.StartsWith("..."))
                {
                    lineSearchText = lineSearchText.Substring(3);
                }

                string logDate = logMass[0];
                lineSearchText = string.Format("{0} - {1}\r\n", logDate, lineSearchText);
                return lineSearchText;
            }
            return String.Empty;
        }

        private void SetFuncs(Action<string> addSearchResult, Action<string> addLog, Func<bool> isStopWork)
        {
            _AddSearchResult = addSearchResult;
            _AddLog = addLog;
            _IsStopWork = isStopWork;
        }
        public void AddSearchResult(string message)
        {
            if (_AddSearchResult != null)
            {
                _AddSearchResult(message);
            }
        }
        public void AddLog(string message)
        {
            if (_AddLog != null)
            {
                _AddLog(message);
            }
        }
        public bool IsStopWork()
        {
            if (_IsStopWork != null)
            {
                bool isStop = _IsStopWork();
                return isStop;
            }
            return false;
        }
        #endregion
    }
}
